// -----------------------------
// Author: 		Dhaenens Gert	
// Creation: 	2/27/2015 8:12:15 PM				
// -----------------------------

#include "SpriteBatch.h"

#include "Engine.h"
#include "GraphicsManager.h"

#include "PlatformProvider.h"
#include "IGraphicsDevice.h"
#include "ITexture.h"
#include "IMutex.h"

#include "AutoLock.h"

#include "Sprite.h"

#include "PosTexShader.h"
#include "PosColTexShader.h"
#include "PosTexNegShader.h"
#include "PosColTexNegShader.h"

namespace Flow
{

	/*
	struct DrawCall
	{
		ITexture*		Texture;
		Shader*			Shader;
		Matrix			WorldMatrix;
		Matrix			ViewMatrix;
		UInt32			Layer;
	};


	// Drawcall sorter
	// Priority: Layer > Shader > Texture
	Bool SortDrawCall(const DrawCall& a, const DrawCall& b)
	{
		// Sort by Layer
		if (a.Layer != b.Layer)
			return a.Layer < b.Layer;

		// Sort by Shader
		if (a.Shader != b.Shader)
			return (UInt32)a.Shader < (UInt32)b.Shader;

		// Sort by Texture
		if (a.Texture != b.Texture)
			return (UInt32)a.Texture < (UInt32)b.Texture;

		return false;
	}
	*/

	PosTexShader* SpriteBatch::s_lpPosTexShader				= nullptr;
	PosColTexShader* SpriteBatch::s_lpPosColTexShader		= nullptr;
	PosTexNegShader* SpriteBatch::s_lpPosTexNegShader		= nullptr;
	PosColTexNegShader* SpriteBatch::s_lpPosColTexNegShader	= nullptr;

	void SpriteBatch::LoadShaders(ShaderManager* lpShaderManager)
	{
		s_lpPosTexShader = new PosTexShader(lpShaderManager);
		s_lpPosColTexShader = new PosColTexShader(lpShaderManager);
		s_lpPosTexNegShader = new PosTexNegShader(lpShaderManager);
		s_lpPosColTexNegShader = new PosColTexNegShader(lpShaderManager);
	}
	void SpriteBatch::UnloadShaders()
	{
		delete s_lpPosColTexNegShader;
		delete s_lpPosTexNegShader;
		delete s_lpPosColTexShader;
		delete s_lpPosTexShader;
	}

	SpriteBatch::SpriteBatch()
		: m_Layer(0)
		, m_QueueLock(nullptr)
		, m_LayerLock(nullptr)
	{
	}

	SpriteBatch::~SpriteBatch()
	{
		SafeReleaseInterface(&m_LayerLock);
		SafeReleaseInterface(&m_QueueLock);
	}

	Bool SpriteBatch::Initialize()
	{
		m_QueueLock = PlatformProvider::QueryInterface<IMutex>("Mutex");
		ASSERT(m_QueueLock);

		m_LayerLock = PlatformProvider::QueryInterface<IMutex>("Mutex");
		ASSERT(m_LayerLock);

		return true;
	}

	void SpriteBatch::Begin()
	{
		// Reset
		SetLayer(0);
	}
	void SpriteBatch::End(IGraphicsDevice* lpDevice, IMutex* lpGraphicsDeviceLock)
	{
		Color clearColor = Engine::ClearColor;

		lpGraphicsDeviceLock->Lock();
		lpDevice->Begin(clearColor.r, clearColor.g, clearColor.b);

		lpDevice->End();
		lpGraphicsDeviceLock->Unlock();
	}

	void SpriteBatch::SetLayer(UInt32 layer)
	{
		AutoLock lock(m_LayerLock);
		m_Layer = layer;
	}
	UInt32 SpriteBatch::GetLayer() const
	{
		return m_Layer;
	}

	void SpriteBatch::IncreaseLayer()
	{
		AutoLock lock(m_LayerLock);
		++m_Layer;
	}
	void SpriteBatch::DecreaseLayer()
	{
		AutoLock lock(m_LayerLock);
		--m_Layer;
	}

	IMutex* SpriteBatch::GetLayerLock() const
	{
		return m_LayerLock;
	}

	void SpriteBatch::Draw(Sprite* lpSprite, const Vector2& position, SpriteEffect::Enum effect)
	{
		Draw(lpSprite, position, m_Layer, effect);
	}
	void SpriteBatch::Draw(Sprite* lpSprite, const Vector2& position, UInt32 layer, SpriteEffect::Enum effect)
	{
		
	}

	void SpriteBatch::DrawRotatedCenter(Sprite* lpSprite, const Vector2& position, Float rotationCenter, SpriteEffect::Enum effect)
	{
		DrawRotatedCenter(lpSprite, position, rotationCenter, m_Layer, effect);
	}
	void SpriteBatch::DrawRotatedCenter(Sprite* lpSprite, const Vector2& position, Float rotationCenter, UInt32 layer, SpriteEffect::Enum effect)
	{
	}

	void SpriteBatch::DrawRotatedPivot(Sprite* lpSprite, const Vector2& position, Float rotation, const Vector2& pivot, SpriteEffect::Enum effect)
	{
		DrawRotatedPivot(lpSprite, position, rotation, pivot, m_Layer, effect);
	}
	void SpriteBatch::DrawRotatedPivot(Sprite* lpSprite, const Vector2& position, Float rotation, const Vector2& pivot, UInt32 layer, SpriteEffect::Enum effect)
	{

	}
}